/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H
#define ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H

#include "plugins/ecmascript/runtime/class_linker/program_object.h"
#include "plugins/ecmascript/runtime/js_tagged_value.h"
#include "plugins/ecmascript/runtime/js_thread.h"

namespace ark::ecmascript {
class GlobalEnv;
class JSArray;

class SlowRuntimeStub {
public:
    /* -------------- Common API Begin, Don't change those interface!!! ----------------- */
    static JSTaggedValue CallSpreadDyn(JSThread *thread, JSTaggedValue func, JSTaggedValue obj, JSTaggedValue array);
    static JSTaggedValue NegDyn(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue AsyncFunctionEnter(JSThread *thread);
    static JSTaggedValue ToNumber(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue NotDyn(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue IncDyn(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue DecDyn(JSThread *thread, JSTaggedValue value);
    static void ThrowDyn(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue GetPropIterator(JSThread *thread, JSTaggedValue value);
    static void ThrowConstAssignment(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue Add2Dyn(JSThread *thread, EcmaVM *ecmaVm, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue Sub2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue Mul2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue Div2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue Mod2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue EqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue NotEqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue LessDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue LessEqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue GreaterDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);
    static JSTaggedValue GreaterEqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right);

    static JSTaggedValue ToJSTaggedValueWithInt32(JSThread *thread, JSTaggedValue value);
    static JSTaggedValue ToJSTaggedValueWithUint32(JSThread *thread, JSTaggedValue value);

    static JSTaggedValue DelObjProp(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop);
    static JSTaggedValue NewObjDynRange(JSThread *thread, uint16_t argsCount, JSTaggedValue func,
                                        JSTaggedValue newTarget, JSTaggedType *stkargs);
    static JSTaggedValue CreateObjectWithExcludedKeys(JSThread *thread, uint16_t numKeys, JSTaggedValue objVal,
                                                      JSTaggedType *stkargs);
    static JSTaggedValue ExpDyn(JSThread *thread, JSTaggedValue base, JSTaggedValue exponent);
    static JSTaggedValue IsInDyn(JSThread *thread, JSTaggedValue prop, JSTaggedValue obj);
    static JSTaggedValue InstanceofDyn(JSThread *thread, JSTaggedValue obj, JSTaggedValue target);

    static JSTaggedValue NewLexicalEnvDyn(JSThread *thread, uint16_t numVars);
    static JSTaggedValue CreateIterResultObj(JSThread *thread, JSTaggedValue value, bool done);

    static JSTaggedValue CreateGeneratorObj(JSThread *thread, JSTaggedValue genFunc);
    static JSTaggedValue SetGeneratorState(JSThread *thread, JSTaggedValue genObj, uint8_t state);
    static JSTaggedValue CreateAsyncGeneratorObj(JSThread *thread, JSTaggedValue genFunc);
    static JSTaggedValue SuspendGenerator(JSThread *thread, JSTaggedValue genObj, JSTaggedValue value);
    static JSTaggedValue SuspendAsyncGenerator(JSThread *thread, JSTaggedValue asyncGenObj, JSTaggedValue value);
    static JSTaggedValue AsyncFunctionAwait(JSThread *thread, JSTaggedValue asyncFuncObj, JSTaggedValue value);
    static JSTaggedValue AsyncFunctionResolveOrReject(JSThread *thread, JSTaggedValue asyncFuncObj, JSTaggedValue value,
                                                      bool isResolve);
    static JSTaggedValue AsyncGeneratorResolve(JSThread *thread, JSTaggedValue asyncGenObj, JSTaggedValue value);
    static JSTaggedValue AsyncGeneratorReject(JSThread *thread, JSTaggedValue asyncGenObj, JSTaggedValue value);
    static JSTaggedValue NewObjSpreadDyn(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget,
                                         JSTaggedValue array);
    static void ThrowTdz(JSThread *thread, JSTaggedValue bindingName);
    static void ThrowIfNotObject(JSThread *thread);
    static void ThrowThrowNotExists(JSThread *thread);
    static void ThrowPatternNonCoercible(JSThread *thread);
    static JSTaggedValue ThrowIfSuperNotCorrectCall(JSThread *thread, uint16_t index, JSTaggedValue thisValue);
    static void ThrowDeleteSuperProperty(JSThread *thread);

    static JSTaggedValue StOwnByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value);
    static JSTaggedValue StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop,
                                                JSTaggedValue value);
    static JSTaggedValue StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value);
    static JSTaggedValue StOwnByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
                                      const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
    static JSTaggedValue StOwnByValueWithNameSet(JSThread *thread, JSHandle<JSTaggedValue> obj,
                                                 JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> value);
    static JSTaggedValue CreateEmptyArray(JSThread *thread, ObjectFactory *factory, JSHandle<GlobalEnv> globalEnv);
    static JSTaggedValue CreateEmptyObject(JSThread *thread, ObjectFactory *factory, JSHandle<GlobalEnv> globalEnv);
    static JSTaggedValue CreateObjectWithBuffer(JSThread *thread, ObjectFactory *factory, JSObject *literal);
    static JSTaggedValue CreateObjectHavingMethod(JSThread *thread, ObjectFactory *factory, JSObject *literal,
                                                  JSTaggedValue env, ConstantPool *constpool);
    static JSTaggedValue SetObjectWithProto(JSThread *thread, JSTaggedValue proto, JSTaggedValue obj);
    static JSTaggedValue CreateArrayWithBuffer(JSThread *thread, ObjectFactory *factory, JSArray *literal);

    static JSTaggedValue GetMethod(JSThread *thread, JSTaggedValue object, JSTaggedValue propKey);
    static JSTaggedValue GetTemplateObject(JSThread *thread, JSTaggedValue literal);
    static JSTaggedValue GetNextPropName(JSThread *thread, JSTaggedValue iter);
    static JSTaggedValue CopyDataProperties(JSThread *thread, JSTaggedValue dst, JSTaggedValue src);

    static JSTaggedValue GetUnmappedArgs(JSThread *thread, uint32_t actualNumArgs, JSTaggedType *stkargs);
    static JSTaggedValue CopyRestArgs(JSThread *thread, uint32_t restNumArgs, JSTaggedType *stkargs);
    static JSTaggedValue GetIterator(JSThread *thread, JSTaggedValue obj, bool async = false,
                                     JSTaggedValue method = JSTaggedValue::Hole());
    static JSTaggedValue CloseIterator(JSThread *thread, JSTaggedValue iter);
    static JSTaggedValue ImportModule(JSThread *thread, JSTaggedValue moduleName);
    static void StModuleVar(JSThread *thread, JSTaggedValue exportName, JSTaggedValue exportObj);
    static void CopyModule(JSThread *thread, JSTaggedValue srcModule);
    static JSTaggedValue LdModvarByName(JSThread *thread, JSTaggedValue moduleObj, JSTaggedValue itemName);

    static JSTaggedValue ClassFieldAdd(JSThread *thread, JSTaggedValue obj, JSTaggedValue propName,
                                       JSTaggedValue value);
    static void DefineClassPrivateFields(JSThread *thread, ConstantPool *constpool, JSTaggedValue env,
                                         JSTaggedValue ctor, JSTaggedValue privateBuf);
    static JSTaggedValue ClassPrivateMethodOrAccessorAdd(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj);
    static JSTaggedValue ClassPrivateFieldAdd(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj,
                                              JSTaggedValue propName, JSTaggedValue value);
    static JSTaggedValue ClassPrivateFieldGet(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj,
                                              JSTaggedValue propName);
    static JSTaggedValue ClassPrivateFieldSet(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj,
                                              JSTaggedValue propName, JSTaggedValue value);
    static JSTaggedValue ClassPrivateFieldIn(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj,
                                             JSTaggedValue propName);

    static JSTaggedValue CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags);

    static JSTaggedValue DefineGetterSetterByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop,
                                                   JSTaggedValue getter, JSTaggedValue setter, bool flag);

    static JSTaggedValue LdObjByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, bool callGetter,
                                      JSTaggedValue receiver);
    static JSTaggedValue StObjByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value);
    static JSTaggedValue LdObjByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, bool callGetter,
                                     JSTaggedValue receiver);
    static JSTaggedValue StObjByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value);
    static JSTaggedValue LdObjByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, bool callGetter,
                                      JSTaggedValue receiver);
    static JSTaggedValue StObjByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value);
    static JSTaggedValue TryLdGlobalByName(JSThread *thread, JSTaggedValue global, JSTaggedValue prop);
    static JSTaggedValue LdGlobalVar(JSThread *thread, JSTaggedValue global, JSTaggedValue prop);
    static JSTaggedValue StGlobalVar(JSThread *thread, JSTaggedValue prop, JSTaggedValue value);
    static JSTaggedValue StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index, JSTaggedValue src);

    static JSTaggedValue DefineGeneratorFunc(JSThread *thread, JSMethod *method);
    static JSTaggedValue DefineAsyncFunc(JSThread *thread, JSMethod *method);
    static JSTaggedValue DefineAsyncGeneratorFunc(JSThread *thread, JSMethod *method);
    static JSTaggedValue DefineNCFuncDyn(JSThread *thread, JSMethod *method);
    static JSTaggedValue DefinefuncDyn(JSThread *thread, JSMethod *method);
    static JSTaggedValue NewClassFunc(JSThread *thread, JSMethod *method);

    static JSTaggedValue DefineClass(JSThread *thread, JSFunction *func, TaggedArray *literal, JSTaggedValue proto,
                                     JSTaggedValue lexenv, ConstantPool *constpool);
    static JSTaggedValue SuperCall(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, uint16_t argsCount,
                                   JSTaggedType *stkargs);
    static JSTaggedValue SuperCallSpread(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget,
                                         JSTaggedValue array);
    static JSTaggedValue DefineMethod(JSThread *thread, JSMethod *method, const JSHandle<JSTaggedValue> &homeObject);
    static JSTaggedValue LdSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue thisFunc);
    static JSTaggedValue StSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value,
                                        JSTaggedValue thisFunc);
    static JSTaggedValue NotifyInlineCache(JSThread *thread, JSFunction *func, JSMethod *method);
    static JSTaggedValue ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc);

    static JSTaggedValue ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal, JSTaggedValue base,
                                      JSTaggedValue lexenv, ConstantPool *constpool);
    static JSTaggedValue CloneClassFromTemplate(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base,
                                                JSTaggedValue lexenv, ConstantPool *constpool);
    static JSTaggedValue SetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length);

    static JSTaggedValue LdEvalVar(JSThread *thread, JSTaggedValue name, JSTaggedValue evalBindings);
    static JSTaggedValue StEvalVar(JSThread *thread, JSTaggedValue name, JSTaggedValue evalBindings,
                                   JSTaggedValue value);
    /* -------------- Common API End, Don't change those interface!!! ----------------- */

    static JSTaggedValue ThrowTypeError(JSThread *thread, const char *message);

private:
    static JSTaggedValue ThrowSyntaxError(JSThread *thread, const char *message);
    static JSTaggedValue GetCallSpreadArgs(JSThread *thread, JSTaggedValue array);
    static JSTaggedValue SetClassInheritanceRelationship(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base);
};
}  // namespace ark::ecmascript
#endif  // ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H
